﻿using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.OpenApi.Models;
using ProductService.Data;
using Volo.Abp;
using Volo.Abp.Uow;
using Volo.Abp.AspNetCore.MultiTenancy;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared;
using Volo.Abp.AspNetCore.Serilog;
using Volo.Abp.Autofac;
using Volo.Abp.AutoMapper;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.MySQL;
using Volo.Abp.Localization;
using Volo.Abp.Localization.ExceptionHandling;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Swashbuckle;
using Volo.Abp.Security.Claims;
using Volo.Abp.UI.Navigation.Urls;
using Volo.Abp.Validation.Localization;
using Volo.Abp.VirtualFileSystem;
using Volo.Abp.AspNetCore.Mvc.AntiForgery;
using Ebusiness_Framework.Consul;
using Google.Protobuf.WellKnownTypes;
using Ebusiness_Framework.RegisterCenter;
using Framework;
using Ebusiness_Framework.SkyAPMConfig;
using Ebusiness_Framework.Evebtbus;
using Ebusiness_Framework.DistributedTransaction;
using Distributed_AuthenticationService.DistributedAuthorization;
using OpenIddict.Validation.AspNetCore;
using static Microsoft.AspNetCore.Razor.Language.TagHelperMetadata;
using Microsoft.AspNetCore.Mvc.Filters;
using Common.Extenions;
//using Ebusiness_Framework.ResourcesMonitoring;

namespace ProductService;

[DependsOn(
    // ABP Framework packages
    typeof(AbpAspNetCoreMvcModule),
    typeof(AbpAutofacModule),
    typeof(AbpAutoMapperModule),
    typeof(AbpEntityFrameworkCoreMySQLModule),
    typeof(AbpSwashbuckleModule),
    typeof(AbpAspNetCoreSerilogModule)
     , typeof(FrameworkModule)
)]
public class ProductServiceModule : AbpModule
{
    
    public override void PreConfigureServices(ServiceConfigurationContext context)
    {
        var hostingEnvironment = context.Services.GetHostingEnvironment();
        var configuration = context.Services.GetConfiguration();

        context.Services.PreConfigure<AbpMvcDataAnnotationsLocalizationOptions>(options =>
        {
            
        });
    }

    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        var hostingEnvironment = context.Services.GetHostingEnvironment();
        var configuration = context.Services.GetConfiguration();


        ConfigureAuthentication(context);
        ConfigureBundles();
        ConfigureUrls(configuration);
        ConfigureAutoMapper(context);
        ConfigureSwagger(context.Services, configuration);
        //ConfigureAutoApiControllers();
        ConfigureCors(context, configuration);
        ConfigureEfCore(context);
        //关闭xss攻击
        ConfigAntiforgery();
        //配置服务扩展
        ConfigServiceExtention(context, configuration);
    }

    /// <summary>
    /// 配置服务扩展
    /// </summary>
    /// <param name="configuration"></param>
    private void ConfigServiceExtention(ServiceConfigurationContext context, IConfiguration configuration)
    {
        #region 注册中心
        {
            //注册中心
            context.Services.AddRegisterCenter(configuration);
        }
        #endregion

        #region 配置链路监控
        {
            //配置链路监控
            //context.Services.UseSkyAPM();
        }
        #endregion

        #region 集成DotNetCore.CAP 事件总线
        {
            // 5、集成DotNetCore.CAP
            //context.Services.UseEventBus<ProductServiceDbContext>(configuration);
        }
        #endregion

        #region 微服务-分布式事务servicecomb-pack
        {
            // 3、配置Servceicomb-pack
            //context.Services.UseDistributedTransaction(configuration);
        }
        #endregion

        #region 集成使用资源监控
        {
            //context.Services.AddResourcesMoniter(configuration);
        }
        #endregion

        #region 分布式认证中心
        {
            //context.Services.AddOpeniddictValidationDistributedAuthorization(configuration);
        }
        #endregion

        #region  结果集和异常统一封装
        {
            //context.Services.AddCommonResultException();
        }
        #endregion
    }

    /// <summary>
    /// 关闭xss攻击
    /// </summary>
    private void ConfigAntiforgery()
    {
        Configure<AbpAntiForgeryOptions>(option =>
        {
            option.AutoValidate = false;
        });
    }

    private void ConfigureAuthentication(ServiceConfigurationContext context)
    {
        context.Services.Configure<AbpClaimsPrincipalFactoryOptions>(options =>
        {
            options.IsDynamicClaimsEnabled = true;
        });
    }

    private void ConfigureBundles()
    {
        Configure<AbpBundlingOptions>(options =>
        {
            options.StyleBundles.Configure(
                LeptonXLiteThemeBundles.Styles.Global,
                bundle => { bundle.AddFiles("/global-styles.css"); }
            );
        });
    }

    private void ConfigureUrls(IConfiguration configuration)
    {
        Configure<AppUrlOptions>(options =>
        {
            options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"];
            options.RedirectAllowedUrls.AddRange(configuration["App:RedirectAllowedUrls"]?.Split(',') ?? Array.Empty<string>());

            options.Applications["Angular"].RootUrl = configuration["App:ClientUrl"];
        });
    }

    private void ConfigureAutoApiControllers()
    {
        Configure<AbpAspNetCoreMvcOptions>(options =>
        {
            options.ConventionalControllers.Create(typeof(ProductServiceModule).Assembly);
        });
    }

    private void ConfigureSwagger(IServiceCollection services, IConfiguration configuration)
    {
        services.AddAbpSwaggerGenWithOAuth(
            configuration["AuthServer:Authority"]!,
            new Dictionary<string, string>
            {
                    {"ProductService", "ProductService API"}
            },
            options =>
            {
                options.SwaggerDoc("v1", new OpenApiInfo { Title = "ProductService API", Version = "v1" });
                options.DocInclusionPredicate((docName, description) => true);
                options.CustomSchemaIds(type => type.FullName);
            });
    }

    private void ConfigureAutoMapper(ServiceConfigurationContext context)
    {
        context.Services.AddAutoMapperObjectMapper<ProductServiceModule>();
        Configure<AbpAutoMapperOptions>(options =>
        {
            /* Uncomment `validate: true` if you want to enable the Configuration Validation feature.
             * See AutoMapper's documentation to learn what it is:
             * https://docs.automapper.org/en/stable/Configuration-validation.html
             */
            options.AddMaps<ProductServiceModule>(/* validate: true */);
        });
    }

    private void ConfigureCors(ServiceConfigurationContext context, IConfiguration configuration)
    {
        context.Services.AddCors(options =>
        {
            options.AddDefaultPolicy(builder =>
            {
                builder
                    .WithOrigins(
                        configuration["App:CorsOrigins"]?
                            .Split(",", StringSplitOptions.RemoveEmptyEntries)
                            .Select(o => o.RemovePostFix("/"))
                            .ToArray() ?? Array.Empty<string>()
                    )
                    .WithAbpExposedHeaders()
                    .SetIsOriginAllowedToAllowWildcardSubdomains()
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowCredentials();
            });
        });
    }


    private void ConfigureEfCore(ServiceConfigurationContext context)
    {
        context.Services.AddAbpDbContext<ProductServiceDbContext>(options =>
        {
            /* You can remove "includeAllEntities: true" to create
             * default repositories only for aggregate roots
             * Documentation: https://docs.abp.io/en/abp/latest/Entity-Framework-Core#add-default-repositories
             */
            options.AddDefaultRepositories(includeAllEntities: true);
        });

        Configure<AbpDbContextOptions>(options =>
        {
            options.Configure(configurationContext =>
            {
                configurationContext.UseMySQL();
            });
        });

    }

    public override void OnApplicationInitialization(ApplicationInitializationContext context)
    {
        var app = context.GetApplicationBuilder();
        var env = context.GetEnvironment();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        if (!env.IsDevelopment())
        {
            app.UseErrorPage();
        }

        app.UseCorrelationId();
        app.UseStaticFiles();
        app.UseRouting();
        app.UseCors();
        app.UseAuthentication();

        app.UseUnitOfWork();
        app.UseDynamicClaims();
        app.UseAuthorization();

        app.UseSwagger();
        app.UseAbpSwaggerUI(options =>
        {
            options.SwaggerEndpoint("/swagger/v1/swagger.json", "ProductService API");

            var configuration = context.GetConfiguration();
            options.OAuthClientId(configuration["AuthServer:SwaggerClientId"]);
            options.OAuthScopes("ProductService");
        });

        app.UseAbpSerilogEnrichers();
        app.UseConfiguredEndpoints();
        //配置中间件扩展
        ConfigMiddlewareExtention(app);
    }

    /// <summary>
    /// 配置中间件扩展
    /// </summary>
    private void ConfigMiddlewareExtention(IApplicationBuilder app)
    {
        #region 配置中心
        {
            //app.UseRegisterCenter();
        }
        #endregion

        #region 集成资源监控Prometheus
        {
            // 3、集成prometheus-net.AspNetCore
            //app.UseResourcesMoniter();

            //app.UseResourceMonitor();
        }
        #endregion
    }
}
